Défi EGC 2024¶

import¶

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from scripts.data_frame_generator import generate_external_time_series,generate_global_time_series, generate_blockchain_by_actor, min_max_norm,std_scale
from scripts.best_correlation import compute_best_correlation,compute_best_correlation_by_col,display_correlation_by_col
from scripts.best_correlation import get_corr_mat
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import seaborn as sns
from scipy.stats import gaussian_kde

Récupération et prétraitement de de la donnée¶

In [2]:
# Récupération des séries temporelles extérieures.
external_df = generate_external_time_series("timeseries/external.csv")

# Récupération des données des 100 plus grands acteurs de la blockchain.
block_chain_by_actor_df = generate_blockchain_by_actor('timeseries/blockchain_by_actor.csv')

# Récupération des données globales.
global_df = generate_global_time_series('timeseries/global.csv')

Travail sur la donnée¶

Affichage du HashRate et du prix en dollars¶

In [3]:
# Normalisation de la data frame
std_scaler = StandardScaler()
df1_normalized = std_scaler.fit_transform(external_df)
df1_normalized = pd.DataFrame(np.array(df1_normalized, dtype=np.float64), columns=external_df.columns,index=external_df.index)

# Lissage de la série temporelle
df_rolling = df1_normalized.rolling(window=7).mean()

# Création de la figure Plotly Express
fig = px.line(df_rolling,x=df_rolling.index,  y=["HashRate", "PriceUSD"],
              title="Evolution du HashRate et du prix du Bitcoin",
              labels={"value": "Valeur normalisée", "variable": "Variables", "Date": df_rolling.index.name},
              template="simple_white")

# Affichage de la figure
fig.show()

Evaluation des correlation entre HashRate et le prix du Bitcoin en Dollar¶

En regardant les précédentes courbes affichées on peut remarquer que le HashRate et le prix en dollars augmentent de mannière comparable. Mesurons maintenant leur niveau de corrélation par la corrélation de Pearson.

In [4]:
correlation_matrix = external_df.corr()
correlation_matrix
Out[4]:
PriceUSD HashRate
PriceUSD 1.000000 0.937447
HashRate 0.937447 1.000000

On peut remarquer ici que le score de correlation de Pearson entre le PriceUSD et le HashRate est de 0.93, ce qui signifie que les PriceUSD et Hashrate on une relation linéaire qui est proche.

Travail sur les 100 principaux acteurs de la blockcahin¶

On veut chercher ici à trouver des correlation sur l'évolution de chaque acteurs entre eux à savoir si deux acteurs ont une activité qui évolue de manière similaire comme il a été fait pour l'analyse du HashRate et du cours du Bitcoin.

On peut alors se poser la question si l'activité de certains groupes d'acteurs sont corrélées entre elles.

In [5]:
# Nom de la colonne à analyser dans le block_chain_by_actor_df
column_to_analyze = 'received'
# Appel d'une fonction déterminant le couple d'acteurs ayant le meilleur coefficient de corrélation 
max_index,max_col, max_value = compute_best_correlation_by_col(block_chain_by_actor_df,column_to_analyze)
print(f"La valeur maximale est {max_value} et elle se trouve à l'index  '{max_index}' dans la colonne '{max_col}'")
La valeur maximale est 0.9021413876901954 et elle se trouve à l'index  'BTCC.com' dans la colonne 'BtcTrade.com'
In [6]:
column_to_analyze = 'received'
max_index, max_col, max_value = compute_best_correlation_by_col(block_chain_by_actor_df, column_to_analyze)

def display_comparison(block_chain_by_actor_df,key1,key2,column_to_analyze,window):
    std_scaler = StandardScaler()
    # Filtrage des données pour la première identité
    df1 = block_chain_by_actor_df[block_chain_by_actor_df['identity'] == key1].copy()
    #df1 = df1.reset_index(drop=True)
    df1[column_to_analyze] = df1[column_to_analyze].rolling(window=window).mean()
    df1_normalized = std_scaler.fit_transform(df1[[column_to_analyze]])
    df1_normalized = pd.DataFrame(np.array(df1_normalized, dtype=np.float64), columns=[column_to_analyze],index=df1.index)
    # Filtrage des données pour la deuxième identité
    df2 = block_chain_by_actor_df[block_chain_by_actor_df['identity'] == key2].copy()
    #df1 = df1.reset_index(drop=True)
    df2[column_to_analyze] = df1[column_to_analyze].rolling(window=window).mean()
    df2_normalized = std_scaler.fit_transform(df2[[column_to_analyze]])
    df2_normalized = pd.DataFrame(np.array(df2_normalized, dtype=np.float64), columns=[column_to_analyze],index=df2.index)

    # Fusion des deux dataframes en un seul
    df = pd.concat([df1, df2])

    # Création de la figure Plotly Express
    fig = px.line(df, x=df.index, y=column_to_analyze, color="identity",
                title=f"Comparison of '{column_to_analyze}' between {key1} and {key2} (Normalized)",
                labels={"value": f"{column_to_analyze} (rolling mean)", "index": "date"})

    # Affichage de la figure
    fig.show()
display_comparison(block_chain_by_actor_df,max_col,max_index,column_to_analyze,10)

On remarque une augmentation du nombre de transactions vers avril 2016 ainsi qu'une baisse vers juillet dans les deux courbes. On notera que le nombre de transaction n'est pas du même ordre de grandeur. C'est ici un exemple de corrélation entre deux acteurs selon un critère fixé en l'occurence le volume reçu. Voyons maintenant si les acteurs suivent une tendance commune sur un critère particulier.

Pondération des Satoshi avec l'évolution du prix en dollars.¶

Afin d'avoir une vision plus globale sur les données des acteurs ainsi que les données externes on décide de convertir les données initialement en satoshi ,telles que sent, received et sum_fee.

In [7]:
SATOSH_PER_BTC = 1e-8
merge_df = pd.merge(block_chain_by_actor_df, external_df[['PriceUSD']], left_index=True, right_index=True)
merge_df['sentUSD'] = merge_df['sent']*SATOSH_PER_BTC*merge_df['PriceUSD']
merge_df['receivedUSD'] =  merge_df['received']*SATOSH_PER_BTC*merge_df['PriceUSD']
merge_df['sum_feeUSD'] =  merge_df['sum_fee']*SATOSH_PER_BTC*merge_df['PriceUSD']
block_chain_by_actor_df = merge_df

Affichage des données corrélées¶

Une fois les prix en satoshi converti en dollars, on décide de créer une data frame, qui pour chaque couple d'acteur et chaque critère va mesurer leur niveau de corrélation.

In [8]:
from scripts.best_correlation import best_correlation_df
best_corr_df = best_correlation_df(block_chain_by_actor_df,0)
best_corr_df = best_corr_df[best_corr_df['related_col'] !='PriceUSD'].sort_values('correlation_rate',ascending=False)
best_corr_df
Out[8]:
actor1 actor2 correlation_rate related_col
58966 107 69697250 0.957747 sum_feeUSD
62953 Bitcoin.de CoinMotion.com 0.950021 sum_feeUSD
63028 Bitstamp.net CoinSpot.com.au 0.946132 sum_feeUSD
63237 CoinMotion.com Paymium.com 0.941566 sum_feeUSD
58998 107 CoinGaming.io 0.940180 sum_feeUSD
... ... ... ... ...
9727 Loanbase.com YoBit.net -0.808506 nb_received
34041 0 BTCJam.com -0.812380 nb_spent
19879 0 Loanbase.com -0.833558 nb_transactions
7602 61 Loanbase.com -0.842981 nb_received
5029 0 Loanbase.com -0.849833 nb_received

58737 rows × 4 columns

  • actor1 actor2 : couples d'acteurs
  • correlation_rate : niveau de corrélation entre les deux acteurs
  • related_col : critère de corrélation

On remarque ici que 92 couples d'acteurs on un indice de corrélation elevé pour leur frais payés en dollars.

In [9]:
related_cols = best_corr_df.related_col.unique()
rows,cols = (len(related_cols)+1)//2,2
counter = 0
fig = make_subplots(rows=rows, cols=cols)
height_per_row,width_per_col = 400,800
for cur_col in related_cols:
    cur_data = best_corr_df[best_corr_df['related_col'] == cur_col]['correlation_rate']
    row,col = (counter)//2 +1,counter%2+1
    fig.add_trace(
    go.Histogram(x=cur_data, histnorm='probability density', name=f'{cur_col} histogramm'),
    row=row, col=col
    )
    fig.add_trace(
        go.Scatter(x=cur_data, y=gaussian_kde(cur_data)(cur_data), mode='lines',name=''),
        row=row, col=col
    )
    counter+=1
    
fig.update_layout(height=height_per_row*rows, width=width_per_col*cols, title_text="Histogrammes")
# Afficher le graphique
fig.show()
Analyse des répartitions des acteurs sur le réseau¶
In [10]:
""" best_corr_df = block_chain_by_actor_df.groupby(by='identity').sum()

def plot_rep(pivot_df: pd.DataFrame, colonne:str):
    fig = px.pie(pivot_df,values=colonne,names=pivot_df.index)
    fig.update_traces(textposition='inside')
    fig.update_layout(title_text=f'{colonne} repartition.')
    fig.show()

#plot_rep(pivot_df, 'received')
cols = 2
rows = 1
fig = make_subplots(rows=rows, cols=cols)

# Ajouter le diagramme camembert pour la colonne 'sum_fee'
fig.add_pie(go.Pie(labels=best_corr_df.index, values=best_corr_df['sum_fee'], name= 'Frais'), row=1, col=1)

# Ajouter le diagramme camembert pour la colonne 'spent'
fig.add_pie(go.Pie(labels=best_corr_df.index, values=best_corr_df['spent'], name='Dépenses'), row=1, col=2)

# Mettre à jour les options de layout
fig.update_traces(textposition='inside')
fig.update_layout(title_text='Repartition des frais et dépenses par date')
fig.show() """
Out[10]:
" best_corr_df = block_chain_by_actor_df.groupby(by='identity').sum()\n\ndef plot_rep(pivot_df: pd.DataFrame, colonne:str):\n    fig = px.pie(pivot_df,values=colonne,names=pivot_df.index)\n    fig.update_traces(textposition='inside')\n    fig.update_layout(title_text=f'{colonne} repartition.')\n    fig.show()\n\n#plot_rep(pivot_df, 'received')\ncols = 2\nrows = 1\nfig = make_subplots(rows=rows, cols=cols)\n\n# Ajouter le diagramme camembert pour la colonne 'sum_fee'\nfig.add_pie(go.Pie(labels=best_corr_df.index, values=best_corr_df['sum_fee'], name= 'Frais'), row=1, col=1)\n\n# Ajouter le diagramme camembert pour la colonne 'spent'\nfig.add_pie(go.Pie(labels=best_corr_df.index, values=best_corr_df['spent'], name='Dépenses'), row=1, col=2)\n\n# Mettre à jour les options de layout\nfig.update_traces(textposition='inside')\nfig.update_layout(title_text='Repartition des frais et dépenses par date')\nfig.show() "
In [11]:
grouped_df = block_chain_by_actor_df.groupby('identity')[['received']].mean()
grouped_df = grouped_df.sort_values('received',ascending=False)
fig = px.bar(grouped_df.head(10), y=['received'], barmode='group')

# Afficher le graphique
fig.show()
In [ ]:

In [12]:
display_correlation_by_col(merge_df.drop("PriceUSD",axis=1),window_size=7,column_to_analyze='received')
In [13]:
merge_df['balanceUSD'] = merge_df['receivedUSD'] - merge_df['sentUSD'] 
merge_df['balance'] = merge_df['received'] - merge_df['sent']